﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Google.GData.Spreadsheets;
using Google.GData.Client;

namespace GoogleFeeder
{
    public class Worksheet
    {
        public readonly Spreadsheet Parent;
        public readonly WorksheetEntry WSheet;

        public Worksheet(Spreadsheet parent, WorksheetEntry wSheet)
        {
            Parent = parent;
            WSheet = wSheet;
        }

        public Cell this[uint col, uint row]
        {
            get
            {
                #region some older approach without CellBag
                /*
                // http://stackoverflow.com/a/11996103/366117

                AtomLink cellFeedLink = WSheet.Links.FindService(GDataSpreadsheetsNameTable.CellRel, null);
                CellQuery query = new CellQuery(cellFeedLink.HRef.ToString());
                // should we do instead: CellQuery cellQuery = new CellQuery(WSheet.CellFeedLink);    ???

                query.MinimumRow = query.MaximumRow = row;
                query.MinimumColumn = query.MaximumColumn = col;

                CellFeed feed = Parent.Parent.Service.Query(query);
                CellEntry cell = feed.Entries[0] as CellEntry;
                return new Cell(this, cell);
                 */
                #endregion

                var addr = new CellAddress(col, row);
                return this[addr];
            }
        }

        public Cell this[CellAddress addr]
        {
            get
            {
                if (!AllCells.Cells.ContainsKey(addr))
                    return null; // don't go into auto-create, so it can be used for "is it empty?" checks, too
                return AllCells.Cells[addr];
            }
        }

        public Cell CreateCell(uint col, uint row)
        {
            var addr = new CellAddress(col, row);
            return CreateCell(addr);
        }

        public Cell CreateCell(CellAddress addr)
        {
            if (AllCells.Cells.ContainsKey(addr))
                return AllCells.Cells[addr]; // just in case it already existed

            CellQuery cellQuery = new CellQuery(WSheet.CellFeedLink);
            cellQuery.MinimumRow = cellQuery.MaximumRow = addr.Row;
            cellQuery.MinimumColumn = cellQuery.MaximumColumn = addr.Col;
            cellQuery.ReturnEmpty = ReturnEmptyCells.yes;
            CellFeed cellFeed = Parent.Parent.Service.Query(cellQuery);
            CellEntry cellEntry = new CellEntry(addr.Row, addr.Col, "-1"); // why "-1"? because empty content wouldn't create the cell
            cellFeed.Insert(cellEntry);

            /* for some reason this fails (cell would be read-only), so for the time being we fix it by doing full re-scan
            var newCell = new Cell(this, cellEntry);
            AllCells.Cells[addr] = newCell;
            return newCell; */
            allCells = null; // == full re-scan
            return this[addr]; // take it from full re-scan
        }

        public IEnumerable<CellAddress> ExistingCells
        {
            get
            {
                return AllCells.Cells.Keys;
            }
        }

        private CellBag allCells = null;
        private CellBag AllCells
        {
            // https://developers.google.com/google-apps/spreadsheets/#working_with_cell-based_feeds

            get
            {
                if (allCells != null)
                    return allCells;
                try
                {
                    allCells = new CellBag(this);
                    CellQuery cellQuery = new CellQuery(WSheet.CellFeedLink);
                    CellFeed cellFeed = Parent.Parent.Service.Query(cellQuery);
                    foreach (CellEntry cell in cellFeed.Entries)
                        allCells.Add(cell.Column, cell.Row, cell);
                    return allCells;
                }
                catch (Exception)
                {
                    allCells = null;
                    throw;
                }
            }
        }
    }
}
